﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Bzure.Common.Core;
using Bzure.Common.Data;
using Bzure.Tools.Templates.Codes;

namespace Bzure.Tools.Templates
{
    public class EntityProviderTemplate : Template
    {
        Dictionary<Type, ORM> ORMs;
        string SectionName;
        string ConnectionName;
        public EntityProviderTemplate(string SectionName, string ConnectionName, Dictionary<Type, ORM> ORMs)
        {
            this.SectionName = SectionName;
            this.ConnectionName = ConnectionName;
            this.ORMs = ORMs;
        }
        public override string TransformText()
        {
            this.WriteLine("/*");
            this.WriteLine("此代码文件由系统自动生成，请不要做任何修改，因为T4模板随时可能重新生成覆盖你的文件");
            this.WriteLine("*/");
            this.WriteLine("using System;");
            this.WriteLine("using System.Collections.Generic;");
            this.WriteLine("using System.Linq;");
            this.WriteLine("using System.Text;");
            this.WriteLine("using System.Data.SqlClient;");
            this.WriteLine("using System.ComponentModel.Composition;");
            this.WriteLine("using Bzure.Common.Data;");
            this.WriteLine("using Bzure.Common.Core;");
            this.WriteLine("using Bzure.Common.Transactions;");




            List<string> namesapces = new List<string>();
            foreach (ORM m in this.ORMs.Values)
            {
                if (!namesapces.Contains(m.EntityType.Namespace))
                    namesapces.Add(m.EntityType.Namespace);
            }
            namesapces.ForEach(m =>
            {
                this.WriteLine(string.Format("using {0};", m));
            });


            this.WriteLine(string.Format("[Export(typeof(IContractFactory<IEntityRequestProcess>)), ExportMetadata(\"ProviderName\", \"{0}\")]", SectionName));
            this.WriteLine(string.Format(" public class {0}_EntityRequestProcessorBuider : IContractFactory<IEntityRequestProcess>", SectionName));
            this.WriteLine(" {");
            this.WriteLine("public float ContractVersion { get { return 1.0F; } }");
            this.WriteLine(" public IEntityRequestProcess Build()");
            this.WriteLine("  {");
            this.WriteLine(string.Format("   return new {0}_EntityRequestProcessor();", SectionName));
            this.WriteLine(" }");
            this.WriteLine("  }");

            this.WriteLine(string.Format("[Export(typeof(IContractFactory<IEntityPostProcess>)), ExportMetadata(\"ProviderName\", \"{0}\")]", SectionName));
            this.WriteLine(string.Format(" public class {0}_EntityPostProcessorBuider : IContractFactory<IEntityPostProcess>", SectionName));
            this.WriteLine(" {");
            this.WriteLine("public float ContractVersion { get { return 1.0F; } }");
            this.WriteLine(" public IEntityPostProcess Build()");
            this.WriteLine("  {");
            this.WriteLine(string.Format("   return new {0}_EntityRequestProcessor();", SectionName));
            this.WriteLine(" }");
            this.WriteLine("  }");


            this.WriteLine(string.Format("  public class {0}_EntityRequestProcessor : Bzure.Common.Data.EntityRequestProcessBase", SectionName));
            this.WriteLine("{");
            this.WriteLine("public override System.Data.Common.DbConnection CreateConnection()");
            this.WriteLine("{");
            this.WriteLine(string.Format("return {0}_ConnectionFactory.GetConnection();", SectionName));
            this.WriteLine(" }");
            this.WriteLine("public override void InitEntityMap(Type TargetType)");
            this.WriteLine("{");


            foreach (ORM m in this.ORMs.Values)
            {
                this.WriteLine(string.Format("AppendEntityHandler<{0}>(TargetType, () => new {1}(this));", m.EntityType.Name, BuildClassName(m.EntityType)));
            }

            this.WriteLine("}");
            this.WriteLine("}");

            this.WriteLine(string.Format("public static class {0}_ConnectionFactory", SectionName));
            this.WriteLine("{");
            this.WriteLine(string.Format("private static string _connectionString = System.Configuration.ConfigurationManager.ConnectionStrings[\"{0}\"].ConnectionString;", ConnectionName));
            this.WriteLine("public static System.Data.Common.DbConnection GetConnection()");
            this.WriteLine(" {");
            this.WriteLine("   return new SqlConnection(_connectionString);");
            this.WriteLine(" }");
            this.WriteLine("}");


            this.WriteLine(string.Format("    public abstract partial class {0}_RepositoryBase :Bzure.Common.Data.TemplateRepository", SectionName));
            this.WriteLine("  {");
            this.WriteLine(string.Format(" public  {0}_RepositoryBase(ITransactionSupport contractProvider)", SectionName));
            this.WriteLine("   : base(contractProvider)");
            this.WriteLine(" {");
            this.WriteLine("  }     ");
            this.WriteLine("}");


            return this.GenerationEnvironment.ToString();
        }
        public string BuildClassName(Type EntityType)
        {
            return string.Format("{0}_Repository", EntityType.Name);
        }
    }
    public class EntityMapTemplate : Template
    {
        public Type EntityType { get; private set; }
        string SectionName;
        string Key;
        Dictionary<string, ColumnMap> columns = default(Dictionary<string, ColumnMap>);
        string tableName = string.Empty;
        public EntityMapTemplate(Type entityType, string SectionName, string TableName, string Key, Dictionary<string, ColumnMap> Columns)
        {
            this.EntityType = entityType;
            this.SectionName = SectionName;
            this.tableName = TableName;
            this.Key = Key;
            this.columns = Columns;
        }
        public override string TransformText()
        {
            this.WriteLine("/*");
            this.WriteLine("此代码文件由系统自动生成，请不要做任何修改，因为T4模板随时可能重新生成覆盖你的文件");
            this.WriteLine("如果你需要扩展实体类的映射文件功能以实现自定义的查询或者更新操作");
            this.WriteLine(string.Format("请使用partial关键字定义类{0}在另外的地代码文件中,不过请注意扩展类的命名空间必须跟原类一致", BuildClassName()));
            this.WriteLine("*/");
            this.WriteLine("using System;");
            this.WriteLine("using System.Collections.Generic;");
            this.WriteLine("using System.Linq;");
            this.WriteLine("using System.Text;");
            this.WriteLine("using Bzure.Common.Data;");
            this.WriteLine("using Bzure.Common.Core;");
            this.WriteLine(string.Format("using {0};", this.EntityType.Namespace));
            this.WriteLine("public partial class ", string.Format("{0}:{1}_RepositoryBase", BuildClassName(), SectionName));
            this.WriteLine("{ ");
            //表名
            this.WriteLine("public override string TableName");
            this.WriteLine("{ get {");
            this.WriteLine(string.Format("     return \"{0}\";", this.tableName));
            this.WriteLine(" }}");
            //静态构造方法
            this.WriteLine(string.Format("static {0}()", BuildClassName()));
            this.WriteLine("{");
            this.WriteLine(string.Format(" {0} entity = new {0}();", this.EntityType.Name));
            this.WriteLine("  Type type = entity.GetType();");
            foreach (ColumnMap map in this.columns.Values)
            {
                this.WriteLine(BuildUpdateMap(map));
            }
            this.WriteLine(string.Format(" ResultMapDelegate<{0}> queryMap = {0}_Map;", this.EntityType.Name));
            this.WriteLine("QueryMapContainer[entity.GetType()] = queryMap;");
            this.WriteLine("}");
            //实例构造方法
            this.WriteLine(string.Format("public {0}(Bzure.Common.Transactions.ITransactionSupport contractProvider)", BuildClassName()));
            this.WriteLine("  : base(contractProvider) { }");
            //实体映射
            this.WriteLine(string.Format("public static {0} {0}_Map(DataReader reader)", this.EntityType.Name));
            this.WriteLine("   {");
            this.WriteLine(string.Format("return new {0}()", this.EntityType.Name));
            this.WriteLine("{");
            List<string> list = new List<string>();
            foreach (ColumnMap map in this.columns.Values)
            {
                list.Add(BuildQueryMap(map));
            }
            this.WriteLine(string.Join(",", list.ToArray()));
            this.WriteLine("    };   }");
            //删除请求
            this.WriteLine("  public override EntityPostRequest ToDeleteRequest(object entity)");
            this.WriteLine("{");
            this.WriteLine(string.Format("  {0} nt = entity as {0};", this.EntityType.Name));
            this.WriteLine(" EntityPostRequest request = new EntityPostRequest(EntityPostRequest.EntityPostMethod.Delete)");
            this.WriteLine("{");
            this.WriteLine("  Entity = nt");
            this.WriteLine("};");
            this.WriteLine(string.Format("  request.AppendConditionMap(nt.{0}, () => nt.{0});", this.Key));
            this.WriteLine(" return request;");
            this.WriteLine("}");
            //更新请求
            this.WriteLine("   public override EntityPostRequest ToUpdateRequest(object entity)");
            this.WriteLine("{");
            this.WriteLine(string.Format("  {0} nt = entity as {0};", this.EntityType.Name));
            this.WriteLine("  EntityPostRequest Request;");
            this.WriteLine("  if (nt.IsPersisted())");
            this.WriteLine("{");
            this.WriteLine("    Request = new EntityPostRequest(EntityPostRequest.EntityPostMethod.Update)");
            this.WriteLine("  {");
            this.WriteLine("     Entity = nt");
            this.WriteLine("  };");
            this.WriteLine(string.Format("  Request.AppendConditionMap(nt.{0}, () => nt.{0});", this.Key));
            this.WriteLine("}");
            this.WriteLine(" else");
            this.WriteLine(" {");
            this.WriteLine("    Request = new EntityPostRequest(EntityPostRequest.EntityPostMethod.Create)");
            this.WriteLine("    {");
            this.WriteLine("   Entity = nt");
            this.WriteLine("   };");
            this.WriteLine(string.Format("   Request.AppendFieldMap(nt.{0}, () => nt.{0});", this.Key));
            this.WriteLine("  }");
            foreach (ColumnMap map in this.columns.Values)
            {
                if (map.FieldName != this.Key)
                    this.WriteLine(string.Format("   Request.AppendFieldMap(nt.{0} , () => nt.{0} );", map.FieldName));
            }

            this.WriteLine("  return Request;");
            this.WriteLine("}");
            //类结束
            this.WriteLine("}");
            return this.GenerationEnvironment.ToString();
        }
        public string BuildClassName()
        {
            return string.Format("{0}_Repository", this.EntityType.Name);
        }
        public string BuildUpdateMap(ColumnMap map)
        {
            return string.Format("AppendDataMap(type, \"{0}\", () => entity.{1});", map.ColumnName, map.FieldName);
        }
        public string BuildQueryMap(ColumnMap map)
        {
            string method = string.Empty;
            Type type = map.MemberExpression.Type;
            if (type == typeof(int))
            {
                method = "GetInt";
            }
            else if (type == typeof(int?))
            {
                method = "GetIntNullable";
            }
            else if (type == typeof(long))
            {
                method = "GetLong";
            }
            else if (type == typeof(long?))
            {
                method = "GetLongNullable";
            }
            else if (type == typeof(Decimal))
            {
                method = "GetDecimal";
            }
            else if (type == typeof(Decimal?))
            {
                method = "GetDecimalNullable";
            }
            else if (type == typeof(DateTime))
            {
                method = "GetDateTime";
            }
            else if (type == typeof(DateTime?))
            {
                method = "GetDateTimeNullable";
            }
            else if (type == typeof(bool))
            {
                method = "GetBoolean";
            }
            else if (type == typeof(bool?))
            {
                method = "GetBooleanNullable";
            }
            else if (type == typeof(Guid))
            {
                method = "GetGuid";
            }
            else if (type == typeof(Guid?))
            {
                method = "GetGuidNullable";
            }
            else if (type == typeof(string))
            {
                method = "GetStringNullable";
            }
            if (method.IsNotNullAndEmpty())
            {
                return string.Format("{0}=reader.{1}(\"{2}\")", map.FieldName, method, map.ColumnName);
            }
            else
            {
                return string.Format("{0}=reader.GetValue<{1}>(\"{2}\")", map.FieldName, map.MemberExpression.Type.Name, map.ColumnName);
            }
        }
    }
    //public class EntityMapTemplate<T> : Template where T : Entity
    //{
    //    string SectionName;
    //    string Key;
    //    Dictionary<string, ColumnMap> columns = default(Dictionary<string, ColumnMap>);
    //    string tableName = string.Empty;
    //    public EntityMapTemplate(string SectionName, string TableName, string Key, Dictionary<string, ColumnMap> Columns)
    //    {
    //        this.SectionName = SectionName;
    //        this.tableName = TableName;
    //        this.Key = Key;
    //        this.columns = Columns;
    //    }
    //    public override string TransformText()
    //    {
    //        this.WriteLine("/*");
    //        this.WriteLine("此代码文件由系统自动生成，请不要做任何修改，因为T4模板随时可能重新生成覆盖你的文件");
    //        this.WriteLine("如果你需要扩展实体类的映射文件功能以实现自定义的查询或者更新操作");
    //        this.WriteLine(string.Format("请使用partial关键字定义类{0}在另外的地代码文件中,不过请注意扩展类的命名空间必须跟原类一致", BuildClassName()));
    //        this.WriteLine("*/");
    //        this.WriteLine("using System;");
    //        this.WriteLine("using System.Collections.Generic;");
    //        this.WriteLine("using System.Linq;");
    //        this.WriteLine("using System.Text;");
    //        this.WriteLine("using Bzure.Common.Data;");
    //        this.WriteLine("using Bzure.Common.Core;");
    //        this.WriteLine(string.Format("using {0};", typeof(T).Namespace));
    //        this.WriteLine("public partial class {0}", string.Format("{0}:{1}_RepositoryBase", BuildClassName(), SectionName));
    //        this.WriteLine("{ ");
    //        //表名
    //        this.WriteLine("public override string TableName");
    //        this.WriteLine("{ get {");
    //        this.WriteLine(string.Format("     return \"{0}\";", this.tableName));
    //        this.WriteLine(" }}");
    //        //静态构造方法
    //        this.WriteLine(string.Format("static {0}()", BuildClassName()));
    //        this.WriteLine("{");
    //        this.WriteLine(string.Format(" {0} entity = new {0}();", typeof(T).Name));
    //        this.WriteLine("  Type type = entity.GetType();");
    //        foreach (ColumnMap map in this.columns.Values)
    //        {
    //            this.WriteLine(BuildUpdateMap(map));
    //        }
    //        this.WriteLine(string.Format(" ResultMapDelegate<{0}> queryMap = {0}_Map;", typeof(T).Name));
    //        this.WriteLine("QueryMapContainer[entity.GetType()] = queryMap;");
    //        this.WriteLine("}");
    //        //实例构造方法
    //        this.WriteLine(string.Format("public {0}(Bzure.Common.Transactions.ITransactionSupport contractProvider)", BuildClassName()));
    //        this.WriteLine("  : base(contractProvider) { }");
    //        //实体映射
    //        this.WriteLine(string.Format("public static {0} {0}_Map(DataReader reader)", typeof(T).Name));
    //        this.WriteLine("   {");
    //        this.WriteLine(string.Format("return new {0}()", typeof(T).Name));
    //        this.WriteLine("{");
    //        List<string> list = new List<string>();
    //        foreach (ColumnMap map in this.columns.Values)
    //        {
    //            list.Add(BuildQueryMap(map));
    //        }
    //        this.WriteLine(string.Join(",", list.ToArray()));
    //        this.WriteLine("    };   }");
    //        //删除请求
    //        this.WriteLine("  public override EntityPostRequest ToDeleteRequest(object entity)");
    //        this.WriteLine("{");
    //        this.WriteLine(string.Format("  {0} nt = entity as {0};", typeof(T).Name));
    //        this.WriteLine(" EntityPostRequest request = new EntityPostRequest(EntityPostRequest.EntityPostMethod.Delete)");
    //        this.WriteLine("{");
    //        this.WriteLine("  Entity = nt");
    //        this.WriteLine("};");
    //        this.WriteLine(string.Format("  request.AppendConditionMap(nt.{0}, () => nt.{0});", this.Key));
    //        this.WriteLine(" return request;");
    //        this.WriteLine("}");
    //        //更新请求
    //        this.WriteLine("   public override EntityPostRequest ToUpdateRequest(object entity)");
    //        this.WriteLine("{");
    //        this.WriteLine(string.Format("  {0} nt = entity as {0};", typeof(T).Name));
    //        this.WriteLine("  EntityPostRequest Request;");
    //        this.WriteLine("  if (nt.IsPersisted())");
    //        this.WriteLine("{");
    //        this.WriteLine("    Request = new EntityPostRequest(EntityPostRequest.EntityPostMethod.Update)");
    //        this.WriteLine("  {");
    //        this.WriteLine("     Entity = nt");
    //        this.WriteLine("  };");
    //        this.WriteLine(string.Format("  Request.AppendConditionMap(nt.{0}, () => nt.{0});", this.Key));
    //        this.WriteLine("}");
    //        this.WriteLine(" else");
    //        this.WriteLine(" {");
    //        this.WriteLine("    Request = new EntityPostRequest(EntityPostRequest.EntityPostMethod.Create)");
    //        this.WriteLine("    {");
    //        this.WriteLine("   Entity = nt");
    //        this.WriteLine("   };");
    //        this.WriteLine(string.Format("   Request.AppendFieldMap(nt.{0}, () => nt.{0});", this.Key));
    //        this.WriteLine("  }");
    //        foreach (ColumnMap map in this.columns.Values)
    //        {
    //            if (map.FieldName != this.Key)
    //                this.WriteLine(string.Format("   Request.AppendFieldMap(nt.{0} , () => nt.{0} );", map.FieldName));
    //        }

    //        this.WriteLine("  return Request;");
    //        this.WriteLine("}");
    //        //类结束
    //        this.WriteLine("}");
    //        return this.GenerationEnvironment.ToString();
    //    }
    //    public static string BuildClassName()
    //    {
    //        return string.Format("{0}_Repository", typeof(T).Name);
    //    }
    //    public string BuildUpdateMap(ColumnMap map)
    //    {
    //        return string.Format("AppendDataMap(type, \"{0}\", () => entity.{1});", map.ColumnName, map.FieldName);
    //    }
    //    public string BuildQueryMap(ColumnMap map)
    //    {
    //        string method = string.Empty;
    //        Type type = map.MemberExpression.Type;
    //        if (type == typeof(int))
    //        {
    //            method = "GetInt";
    //        }
    //        else if (type == typeof(int?))
    //        {
    //            method = "GetIntNullable";
    //        }
    //        else if (type == typeof(long))
    //        {
    //            method = "GetLong";
    //        }
    //        else if (type == typeof(long?))
    //        {
    //            method = "GetLongNullable";
    //        }
    //        else if (type == typeof(Decimal))
    //        {
    //            method = "GetDecimal";
    //        }
    //        else if (type == typeof(Decimal?))
    //        {
    //            method = "GetDecimalNullable";
    //        }
    //        else if (type == typeof(DateTime))
    //        {
    //            method = "GetDateTime";
    //        }
    //        else if (type == typeof(DateTime?))
    //        {
    //            method = "GetDateTimeNullable";
    //        }
    //        else if (type == typeof(bool))
    //        {
    //            method = "GetBoolean";
    //        }
    //        else if (type == typeof(bool?))
    //        {
    //            method = "GetBooleanNullable";
    //        }
    //        else if (type == typeof(Guid))
    //        {
    //            method = "GetGuid";
    //        }
    //        else if (type == typeof(Guid?))
    //        {
    //            method = "GetGuidNullable";
    //        }
    //        else if (type == typeof(string))
    //        {
    //            method = "GetStringNullable";
    //        }
    //        if (method.IsNotNullAndEmpty())
    //        {
    //            return string.Format("{0}=reader.{1}(\"{2}\")", map.FieldName, method, map.ColumnName);
    //        }
    //        else
    //        {
    //            return string.Format("{0}=reader.GetValue<{1}>(\"{2}\")", map.FieldName, map.MemberExpression.Type.Name, map.ColumnName);
    //        }
    //    }
    //}
}
